package com.ls.task.biz.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import com.ls.fw.commons.log.exception.ExceptionsHelper;
import com.ls.fw.data.rdb.impl.mybatis.mapper.entity.Example;
import com.ls.task.bean.JobStatus;
import com.ls.task.bean.QuertzStatus;
import com.ls.task.biz.QuertzBiz;
import com.ls.task.dal.model.SysTask;
import com.ls.task.dal.model.SysTaskTrigger;
import com.ls.task.dal.service.SysTaskService;
import com.ls.task.dal.service.SysTaskTriggerService;
import com.ls.task.utils.TaskUtils;

@Service("quertzBiz")
public class QuertzBizImpl implements QuertzBiz{

	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private SchedulerFactoryBean  quertzManager;
	@Autowired
	private SysTaskService sysTaskService;

	@Autowired
	private SysTaskTriggerService sysTaskTriggerService;
	@Override
	public QuertzStatus status(){
		QuertzStatus status = new QuertzStatus();
		status.setAutoStartup(quertzManager.isAutoStartup());
		status.setRunning(quertzManager.isRunning());
		try {
			status.setInstanceId(quertzManager.getScheduler().getSchedulerInstanceId());
			status.setStartupDt(quertzManager.getScheduler().getMetaData().getRunningSince());
			status.setName(quertzManager.getScheduler().getSchedulerName());
			status.setInStandbyMode(quertzManager.getScheduler().isInStandbyMode());
			status.setShutdown(quertzManager.getScheduler().isShutdown());
			status.setStarted(quertzManager.getScheduler().isStarted());
			status.setExecutedJobTimes(quertzManager.getScheduler().getMetaData().getNumberOfJobsExecuted());
		} catch (SchedulerException e) {
			logger.warn(ExceptionsHelper.getRootCause(e).getMessage(), e);
		}
		try {
			Set<JobKey> set = quertzManager.getScheduler().getJobKeys(GroupMatcher.anyJobGroup());
			if(set != null){
				Set<JobStatus> setJobStatus = new HashSet<JobStatus>();
				status.setJobs(setJobStatus);
				for (JobKey jobKey : set) {
					JobStatus jobStatus = new JobStatus();
					jobStatus.setGroup(jobKey.getGroup());
					jobStatus.setName(jobKey.getName());
					quertzManager.getScheduler().getJobDetail(jobKey);
					List<? extends Trigger>  list1 = quertzManager.getScheduler().getTriggersOfJob(jobKey);
					List<JobStatus.TriggerStatus> ts = new ArrayList<JobStatus.TriggerStatus>();
					jobStatus.setTriggers(ts);
					for (Trigger trigger : list1) {
						JobStatus.TriggerStatus tstatus = new JobStatus.TriggerStatus();
						tstatus.setGroup(trigger.getKey().getGroup());
						tstatus.setName(trigger.getKey().getName());
						tstatus.setEndDt(trigger.getEndTime());
						tstatus.setFireDt(trigger.getFinalFireTime());
						tstatus.setNextDt(trigger.getNextFireTime());
						tstatus.setPreviousDt(trigger.getPreviousFireTime());
						tstatus.setStartDt(trigger.getStartTime());
						tstatus.setStatus(quertzManager.getScheduler().getTriggerState(trigger.getKey()).toString().toLowerCase());
						if(trigger instanceof CronTriggerImpl){
							CronTriggerImpl cronTrigger = (CronTriggerImpl)trigger;
							tstatus.setEndDt(cronTrigger.getEndTime());
							tstatus.setFireDt(cronTrigger.getFinalFireTime());
							tstatus.setNextDt(cronTrigger.getNextFireTime());
							tstatus.setPreviousDt(cronTrigger.getPreviousFireTime());
							tstatus.setStartDt(cronTrigger.getStartTime());
						}else if(trigger instanceof SimpleTriggerImpl){
							SimpleTriggerImpl cronTrigger = (SimpleTriggerImpl)trigger;
							tstatus.setEndDt(cronTrigger.getEndTime());
							tstatus.setFireDt(cronTrigger.getFinalFireTime());
							tstatus.setNextDt(cronTrigger.getNextFireTime());
							tstatus.setPreviousDt(cronTrigger.getPreviousFireTime());
							tstatus.setStartDt(cronTrigger.getStartTime());
						}
						ts.add(tstatus);
					}
					setJobStatus.add(jobStatus);
				}
			}
		} catch (SchedulerException e) {
			logger.warn(ExceptionsHelper.getRootCause(e).getMessage(), e);
		}
		return status;
	}
	
	

	@Override
	public void fire(Long taskId){
		SysTask model = sysTaskService.find(taskId);
		loadOnce(model);
	}

	@Override
	public void fire(){
		Example record = new Example(SysTask.class);
		record.createCriteria().andEqualTo(SysTask.Columns.deleteClass.property(), Boolean.FALSE)
		.andEqualTo(SysTask.Columns.validClass.property(),Boolean.TRUE);
		List<SysTask> list = sysTaskService.selectByExample(record );
		if(list != null && list.size()>0){
			for (SysTask sysTask : list) {
				load(sysTask);
			}
		}
	}
	
	private void loadOnce(SysTask model){
		JobKey key = TaskUtils.jobKey(model);
		try {
			if(!quertzManager.getScheduler().checkExists(key)){
				JobDetail jobDetail = TaskUtils.loadTask(model);
				quertzManager.getScheduler().addJob(jobDetail, false);
			}else{
				JobDetail jobDetail = TaskUtils.loadTask(model);
				quertzManager.getScheduler().addJob(jobDetail, true);
			}
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
		try {
			TriggerKey triggerKey = TaskUtils.triggerKey(null, model);
			if(!quertzManager.getScheduler().checkExists(triggerKey)){
				quertzManager.getScheduler().scheduleJob(TaskUtils.trigger(model));
			}
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
	}
	
	private void load(SysTask model){
		JobKey key = TaskUtils.jobKey(model);
		try {
			if(!quertzManager.getScheduler().checkExists(key)){
				JobDetail jobDetail = TaskUtils.loadTask(model);
				quertzManager.getScheduler().addJob(jobDetail,true);
			} 
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
	}
	private void unload(SysTask model){
		JobKey key = TaskUtils.jobKey(model);
		try {
			if(quertzManager.getScheduler().checkExists(key)){
				quertzManager.getScheduler().deleteJob(key);
			} 
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
	}

	private void load(SysTaskTrigger sysTaskTrigger, SysTask model){
		JobKey key = TaskUtils.jobKey(model);
		try {
			if(!quertzManager.getScheduler().checkExists(key)){
				JobDetail jobDetail = TaskUtils.loadTask(model);
				quertzManager.getScheduler().addJob(jobDetail, false);
			}else{
				JobDetail jobDetail = TaskUtils.loadTask(model);
				quertzManager.getScheduler().addJob(jobDetail, true);
			}
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
		try {
			TriggerKey triggerKey = TaskUtils.triggerKey(sysTaskTrigger, model);
			if(!quertzManager.getScheduler().checkExists(triggerKey)){
				quertzManager.getScheduler().scheduleJob(TaskUtils.trigger(null,sysTaskTrigger,model));
			}
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
	}
	

	private void unload(SysTaskTrigger sysTaskTrigger, SysTask model){
		try {
			TriggerKey triggerKey = TaskUtils.triggerKey(sysTaskTrigger, model);
			if(quertzManager.getScheduler().checkExists(triggerKey)){
				quertzManager.getScheduler().unscheduleJob(triggerKey);
			}
		} catch (SchedulerException e) {
			throw new IllegalArgumentException(ExceptionsHelper.getRootCause(e).getMessage(),e);
		}
	}




	@Override
	public void resumeTriggers(Long... triggerId) throws SchedulerException {
		if(triggerId != null){
			for (Long id : triggerId) {
				SysTaskTrigger model = sysTaskTriggerService.find(id);
				SysTask sysTask = sysTaskService.find(model.getTaskId());
				TriggerKey triggerKey = TaskUtils.triggerKey(model, sysTask);
				if(quertzManager.getScheduler().checkExists(triggerKey)){
					quertzManager.getScheduler().resumeTrigger(triggerKey);
				}
			}
		}
	}



	@Override
	public void resumeAllTriggers() throws SchedulerException {
		quertzManager.getScheduler().resumeTriggers(GroupMatcher.anyTriggerGroup());
	}


	@Override
	public void resumeAllJobs() throws SchedulerException {
		quertzManager.getScheduler().resumeJobs(GroupMatcher.anyJobGroup());
	}



	@Override
	public void pauseAllTriggers() throws SchedulerException {
		quertzManager.getScheduler().pauseTriggers(GroupMatcher.anyTriggerGroup());
	}


	@Override
	public void pauseAllJobs() throws SchedulerException {
		quertzManager.getScheduler().pauseJobs(GroupMatcher.anyJobGroup());
	}

	@Override
	public void resumeJobs(Long... taskId) throws SchedulerException {
		if(taskId != null){
			for (Long id : taskId) {
				SysTask model = sysTaskService.find(id);
				JobKey key = TaskUtils.jobKey(model);
				if(quertzManager.getScheduler().checkExists(key)){
					quertzManager.getScheduler().resumeJob(key);
				} 
			}
		}
	}


	@Override
	public void addJobs(Long... taskId) throws SchedulerException	{
		if(taskId != null){
			for (Long id : taskId) {
				SysTask model = sysTaskService.find(id);
				JobKey key = TaskUtils.jobKey(model);
				if(quertzManager.getScheduler().checkExists(key)){
					quertzManager.getScheduler().addJob(TaskUtils.loadTask(model),true);
				} 
			}
		}
	}

	@Override
	public void pauseTriggers(Long... triggerId) throws SchedulerException {
		if(triggerId != null){
			for (Long id : triggerId) {
				SysTaskTrigger model = sysTaskTriggerService.find(id);
				SysTask sysTask = sysTaskService.find(model.getTaskId());
				TriggerKey triggerKey = TaskUtils.triggerKey(model, sysTask);
				if(quertzManager.getScheduler().checkExists(triggerKey)){
					quertzManager.getScheduler().pauseTrigger(triggerKey);
				}
			}
		}
	}



	@Override
	public void pauseJobs(Long... taskId) throws SchedulerException {
		if(taskId != null){
			for (Long id : taskId) {
				SysTask model = sysTaskService.find(id);
				JobKey key = TaskUtils.jobKey(model);
				if(quertzManager.getScheduler().checkExists(key)){
					quertzManager.getScheduler().pauseJob(key);
				} 
			}
		}
	}



	@Override
	public void deleteJobs(Long... taskId) {
		if(taskId != null){
			for (Long id : taskId) {
				SysTask sysTask = sysTaskService.find(id);
				unload(sysTask);
			}
		}
	}



	@Override
	public void rescheduleJob(Long... triggerId) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public void unscheduleJobs(Long... triggerId) {
		if(triggerId != null){
			for (Long id : triggerId) {
				SysTaskTrigger model = sysTaskTriggerService.find(id);
				SysTask sysTask = sysTaskService.find(model.getTaskId());
				unload(model, sysTask);
			}
		}
	}



	@Override
	public void scheduleJobs(Long... triggerId) {
		if(triggerId!=null){
			for (Long id : triggerId) {
				SysTaskTrigger model = sysTaskTriggerService.find(id);
				SysTask sysTask = sysTaskService.find(model.getTaskId());
				load(model, sysTask);
			}
		}
	}



	@Override
	public void shutdown() throws SchedulerException {
		if(this.quertzManager.getScheduler().isStarted()){
			this.quertzManager.getScheduler().shutdown(true);
		}
	}



	@Override
	public void start() throws SchedulerException {
		if(this.quertzManager.getScheduler().isShutdown()){
			this.quertzManager.getScheduler().start();
		}
	}
}
